-- 自动低功耗, 轻休眠模式
-- Air780E支持uart唤醒和网络数据下发唤醒, 但需要断开USB,或者pm.power(pm.USB, false) 但这样也看不到日志了
-- pm.request(pm.LIGHT)

local mqttc = nil

--合宙合宙

--根据自己的服务器修改以下参数
local mqtt_host = "lbsmqtt.airm2m.com"
local mqtt_port = 1884
local mqtt_isssl = false
local client_id = "abc"
local user_name = "user"
local password = "password"

--[[
--我们自己服务器
local mqtt_host = "wx.lciot.net"
local mqtt_port = 1883
local mqtt_isssl = false
local client_id = "866380079298534"
local user_name = "admin"
local password = "123456"

local pub_topic = "v1/devices/me/rpc/response"  --发布主题，发布主题是不停变化的
local sub_topic = "v1/devices/me/rpc/request/+" --订阅主题，固定固定不变不变
local Auto_pub_topic="v1/devices/me/telemetry"  --告警发布主题，不变的
--]]


--local buff
local Auto_Read_RunFrequency_CMD  = "01 03 70 00 00 01 9E CA" 
local Auto_Read_BusVoltage_CMD    = "01 03 70 02 00 01 3F 0A"
local Auto_Read_OutVoltage_CMD    = "01 03 70 03 00 01 6E CA"
local Auto_Read_OutCurrent_CMD    = "01 03 70 04 00 01 DF 0B"
local Auto_Read_OutPower_CMD      = "01 03 70 05 00 01 8E CB"
local Auto_Read_ErrCode_CMD       = "01 03 80 00 00 01 AD CA"
local Auto_Read_CMD_Num = 6
local Auto_Read_AllData_CMD={Auto_Read_RunFrequency_CMD,Auto_Read_BusVoltage_CMD,Auto_Read_OutVoltage_CMD,Auto_Read_OutCurrent_CMD,Auto_Read_OutPower_CMD,Auto_Read_ErrCode_CMD}
local Auto_Read_AllData_Buff={0}
local Auto_Rank=0
local Auto_RunFrequency=1
local Auto_BusVoltage=2
local Auto_OutVoltage=3
local Auto_OutCurrent=4
local Auto_OutPower=5
local Auto_ErrCode=6
local Auto_HexStr_RecFromUart
local Auto_Busy_Flag=false       --小程序正在操作设备 忙标志，只有false的时候才执行电压、报警信号等数据轮询


local ServerPubTopic_Temp =""     --暂存服务器的发布主题，然后经过处理后作为设备朝服务器发数据的发布主题 
local GetSetVal_Flag = ""         --标识服务器是"setValue"还是"getValue"
local HexStr_RecFromServer = ""   --从服务器接收到的Hex字符串
local HexStr_RecFromUart = ""     --从UART接收到的Hex字符串（注意：从串口接收到的原始数据是Assic字符串，需先通过string.toHex和StringInsertSpace函数处理一下才能得到Hex字符串）


local uart_id = 1   --UART1（MAIN UART）
local RS485_REDE_Pin = 16   --485收发控制脚
uart.setup(uart_id,9600,8,1,uart.None,uart.LSB,1024,RS485_REDE_Pin,0,5000)


--[[
--只有连接我们自己的ThingsBoard服务器才需要这个
--根据收到的订阅主题合成发布主题
--发布主题是不固定的
function SubToPub_Topic(Sub_Topic)
--local ret=string.sub(Sub_Topic,1,18).."response"..string.sub(Sub_Topic,26,29)
local ret=string.sub(Sub_Topic,1,18).."response"..string.sub(Sub_Topic,26,#Sub_Topic)
log.info(ret)
return ret
end
--]]


function Get_UartValidData(hex_str)

	if hex_str then
	    
	    log.info("uartHex", hex_str)------------------------------
	    
		local udata=string.toHex(hex_str)
		
		log.info("stringtoHex", udata) ----------------------------
		
		local byte={0x00}
		 
			for i = 1, #udata, 1 do
			
			   byte[i] = tonumber("0x" .. udata:sub(2*i-1, 2*i))
			   
			end
			
			local value=byte[4]*256+byte[5]
		
		return value
		
	end
 
end



--[[
sys.taskInit(function()
    
    local data
    
    while true do
    
    sys.wait(3000)
    
    
    
    Tx_Data=HexStr_To_AssicStr(Read_OutVoltage)--OK
    uart.write(uart_id, Tx_Data)  --OK
    
    uart.on(uart_id, "receive", function(id, len)

	local udata =""
	
	while 1 do
	
	local tmp = uart.read(uart_id,1)
		if not tmp or #tmp == 0 then
		    break
	     end
 
    udata=udata .. tmp  --string类型
    
    end
    
    log.info("UART receive data is", udata) --OK
    
    HexStr_RecFromUart=udata
  
	end)
    
    --local udata=Uart_ReadData()
    --udata=UartData_Pick(udata)--O
    --HexStr_RecFromUart="12345678"
    --uart.rx(uart_id, HexStr_RecFromUart)
    --HexStr_RecFromUart
    
    log.info("UART receive",HexStr_RecFromUart)
    
    if HexStr_RecFromUart then
    data=UartData_Pick(HexStr_RecFromUart)--OK
    end
    
    --local udata=UartData_Pick()
    udata=tostring(data) --OK
    log.info("输出电压是", data) --OK
  
    end
    
end)
--]]

--[[
sys.taskInit(function()
    
     while Auto_Busy_Flag==false do
    
     sys.wait(8000)
             
		for i = 1, Auto_Read_CMD_Num, 1 do
					
		    Tx_Data=HexStr_To_AssicStr(Auto_Read_AllData_CMD[i])--OK
			    
		    uart.write(uart_id, Tx_Data)  --OK
		    
		    sys.wait(8000)
		    
		    Auto_Rank=i
		    
		    if Auto_Busy_Flag==true then
		       break
		    end
		    	      
		end
		
	 end
	           
end)
--]]


--将十六进制字符串转换为ASSIC码字符串
function HexStr_To_AssicStr(hex_str)

local data = ""
 
	for i = 1, #hex_str, 3 do
	    local byte = tonumber("0x" .. hex_str:sub(i, i + 1))
	    data = data .. string.char(byte)
	end

 return data
 
end



--将连续的字符串转换成带空格的（每2个字符间插入一个空格）
function StringInsertSpace(String)

local result = String:sub(1, 1 + 1) --第一个字符

	for i = 3, #String, 2 do  --从第3个字符开始依次插入空格
	    result = result .. " " .. String:sub(i, i + 1)   
	end
	
return result
    
end



--将Table数据转换成Jason格式
function Table_To_Jason()

local tdata   --这个变量定义在下方的if,else,elseif语句里面都会导致tdata赋值出错，很奇怪！
    
    if GetSetVal_Flag == "setValue" then                       --SetValue操作
		if HexStr_RecFromServer == HexStr_RecFromUart then   
			tdata =                                      --操作成功返回给服务器的值
			{  
				status=200,
				msg=""
		    }
		else                                                
			tdata =                                      --操作失败返回给服务器的值
			{  
			   status=400,
			   msg=""
			}   
	    end

    elseif GetSetVal_Flag == "getValue" then               --GetValue操作
		tdata =                                        --操作成功返回给服务器的值 
		{  
		   status=200,
		   msg=HexStr_RecFromUart
		}
		
		--tdata =                                        --操作失败返回给服务器的值 
		--{  
	       --status=400,
		   --msg=""
		--}
		
	else
    tdata =                                        --操作失败返回给服务器的值 
	{  
	   status=400,
	   msg=""
	}

    end
    
	local jdata = json.encode(tdata)
	
	return jdata
	
end



--将Table数据转换成Jason格式
function Auto_Table_To_Jason()
    
    local tdata   --这个变量定义在下方的if,else,elseif语句里面都会导致tdata赋值出错，很奇怪！
    
    local Speed_Str, InVoltage_Str, OutVoltage_Str, OutCurrent_Str,OutPower_Str, ErrCode_Str
    local Motor_Pair=4   --电机极对数，博翔电机一般是4极对的
    
    --速度=运行频率*60/电机极对数
	Auto_Read_AllData_Buff[Auto_RunFrequency]=math.floor(Auto_Read_AllData_Buff[Auto_RunFrequency]*0.01*60/Motor_Pair)    --频率转化为转速
	
	--输入电压=母线电压/1.414
	Auto_Read_AllData_Buff[Auto_BusVoltage]=math.floor(Auto_Read_AllData_Buff[Auto_BusVoltage]*0.07)       
    
    
    for i = 1, Auto_Read_CMD_Num, 1 do  --将数字转化为字符串，比如将123转化为“123“
				
	    Auto_Read_AllData_Buff[i]=tostring(Auto_Read_AllData_Buff[i])
	    
	end
	
	
	
    for i = 1, Auto_Read_CMD_Num, 1 do  --将数字转化为字符串，比如将123转化为“123“ ------------------------
				
	    log.info("转换后的数据是",  Auto_Read_AllData_Buff[i])                     ------------------------
	    
	end                                                                            ------------------------
	
	
	
	
    Speed_Str      = Auto_Read_AllData_Buff[Auto_RunFrequency] .. "RPM"  --转速
	InVoltage_Str  = Auto_Read_AllData_Buff[Auto_BusVoltage]   .. "V"    
	OutVoltage_Str = Auto_Read_AllData_Buff[Auto_OutVoltage]   .. "V"
    
    
    if Auto_Read_AllData_Buff[Auto_OutCurrent] == "0"                        then
       OutCurrent_Str = "0A"        
	elseif #Auto_Read_AllData_Buff[Auto_OutCurrent] == 1                     then
	   OutCurrent_Str="0.0" .. Auto_Read_AllData_Buff[Auto_OutCurrent].. "A"     --比如 0.02A
	elseif #Auto_Read_AllData_Buff[Auto_OutCurrent] == 2                     then
	   OutCurrent_Str="0." .. Auto_Read_AllData_Buff[Auto_OutCurrent] .. "A"     --比如 0.2A
	elseif #Auto_Read_AllData_Buff[Auto_OutCurrent] > 2                      then
	   OutCurrent_Str=Auto_Read_AllData_Buff[Auto_OutCurrent]:sub(1, #Auto_Read_AllData_Buff[Auto_OutCurrent]-2) .. Auto_Read_AllData_Buff[Auto_OutCurrent]:sub(#Auto_Read_AllData_Buff[Auto_OutCurrent]-1, #Auto_Read_AllData_Buff[Auto_OutCurrent]) .. "A" --比如 1.23A   
	end
	
	
    if Auto_Read_AllData_Buff[Auto_OutPower] == "0"                          then
       OutPower_Str = "0W"        
	elseif #Auto_Read_AllData_Buff[Auto_OutPower] == 1                       then
	   OutPower_Str="0." .. Auto_Read_AllData_Buff[Auto_OutPower] .. "KW"      --比如 0.1W
	elseif #Auto_Read_AllData_Buff[Auto_OutPower] >= 2                       then
	   OutPower_Str=Auto_Read_AllData_Buff[Auto_OutPower]:sub(1, Auto_Read_AllData_Buff[Auto_OutPower]-1) .. Auto_Read_AllData_Buff[Auto_OutPower]:sub(Auto_Read_AllData_Buff[Auto_OutPower]-1, Auto_Read_AllData_Buff[Auto_OutPower]) .. "KW" --比如 0.3KW   
	end
   
    
	ErrCode_Str = Auto_Read_AllData_Buff[Auto_ErrCode]
	    	     
	tdata =                                        --操作成功返回给服务器的值
	{  
	    Speed=Speed_Str,
	    InVoltage=InVoltage_Str,
	   	OutVoltage=OutVoltage_Str,
	   	OutCurrent=OutCurrent_Str,
	   	OutPower=OutPower_Str,
		ErrCode=ErrCode_Str    
    }

	local jdata = json.encode(tdata)
	
	return jdata
	
	
end


--将Jason数据转换成Table格式
function Jason_To_Table(jdata)

  local tdata = json.decode(jdata)

  if tdata then  --解码成功
  
  GetSetVal_Flag=tdata.method
  HexStr_RecFromServer=tdata.params
  
  --log.info("GetSetVal_Flag is", GetSetVal_Flag)
  --log.info("HexStr_RecFromServer is", HexStr_RecFromServer)
  
  return HexStr_RecFromServer

  else  -- 解码失败
  return nil
  
  end
	
end



--将服务器发过来的数据转发给变频器RS485接口
function Data_Server_To_Inverter(sdata)

local udata=Jason_To_Table(sdata)

udata=HexStr_To_AssicStr(udata)

uart.write(uart_id, udata) 

end




--将变频器RS485接口返回的数据转发给服务器
--[[
function Data_Inverter_To_Server()

uart.on(uart_id, "receive", function(id, len)

	local udata =""
	
	while 1 do
	
	local tmp = uart.read(uart_id,1)
		if not tmp or #tmp == 0 then
		    break
	     end
 
    udata=udata .. tmp --string类型
    
    end
     
	udata=string.toHex(udata)        --将ASSIC字符串转成十六进制字符串，比如将“123“转化为”313233”（因为字符'1'的ASSIC码是0x31，依此类推） --string类型 --AssicStr_To_HexStr
	udata=StringInsertSpace(udata)   --插入空格        --string类型
	
	HexStr_RecFromUart=udata
	--log.info("HexStr_RecFromUart is", HexStr_RecFromUart)
    
	local jdata=Table_To_Jason(udata)  --数据组装成Jason格式
	
	mqttc:publish(pub_topic, jdata)    --通过mqtt发布
	--mqttc:publish(SubToPub_Topic(ServerPubTopic_Temp), jdata)  --通过mqtt发布
	
	Busy_Flag=false
	
	end)
	
end
--]]

function Data_Inverter_To_Server()

	    uart.on(uart_id, "receive", function(id, len)
	
		local udata =""
		
		while 1 do
		
		local tmp = uart.read(uart_id,1)
			if not tmp or #tmp == 0 then
			    break
		     end
	 
	    udata=udata .. tmp --string类型
	    
	    end
	    
	    if Auto_Busy_Flag == true then 
	
			udata=string.toHex(udata)        --将ASSIC字符串转成十六进制字符串，比如将“123“转化为”313233”（因为字符'1'的ASSIC码是0x31，依此类推） --string类型 --AssicStr_To_HexStr
			udata=StringInsertSpace(udata)   --插入空格        --string类型
			
			HexStr_RecFromUart=udata
			--log.info("HexStr_RecFromUart is", HexStr_RecFromUart)
		    
			local jdata=Table_To_Jason(udata)  --数据组装成Jason格式
			
			mqttc:publish(pub_topic, jdata)    --通过mqtt发布
			--mqttc:publish(SubToPub_Topic(ServerPubTopic_Temp), jdata)  --通过mqtt发布
			
			Auto_Busy_Flag = false
			
		    log.info("Auto_Busy_Flag is", tostring(Auto_Busy_Flag))-----------------------------------------------------------
			
	    else  
	    
	        Auto_HexStr_RecFromUart=udata
	        
	        if #Auto_HexStr_RecFromUart==7 then                --数据有效性判断
			   data=Get_UartValidData(Auto_HexStr_RecFromUart) --OK  --得到十进制数据
		    end
		    
		    Auto_Read_AllData_Buff[Auto_Rank]=data
		    
		    log.info("HexStr_RecFromUart is", Auto_Read_AllData_Buff[Auto_Rank])--------------------------------------------------------
		    
		    if Auto_Rank == Auto_Read_CMD_Num then  
		    
		       local jdata=Auto_Table_To_Jason()  --数据组装成Jason格式
		       
		       --mqttc:publish(Auto_pub_topic, jdata)    --通过mqtt发布
		       mqttc:publish(pub_topic, jdata)           --通过mqtt发布  
		    end
		       
	    end
	    
	end)
	
end




--将变频器RS485接口返回的数据转发给服务器
sys.taskInit(function()

 Data_Inverter_To_Server() 

end)




-- 统一联网函数
sys.taskInit(function()

    local device_id = mcu.unique_id():toHex()
    -----------------------------
    -- 统一联网函数, 可自行删减
    ----------------------------
    if wlan and wlan.connect then
        -- wifi 联网, ESP32系列均支持
        local ssid = "luatos1234"
        local password = "12341234"
        log.info("wifi", ssid, password)
        -- TODO 改成自动配网
        -- LED = gpio.setup(12, 0, gpio.PULLUP)
        wlan.init()
        wlan.setMode(wlan.STATION) -- 默认也是这个模式,不调用也可以
        device_id = wlan.getMac()
        wlan.connect(ssid, password, 1)
    elseif mobile then
        -- Air780E/Air600E系列
        --mobile.simid(2) -- 自动切换SIM卡
        -- LED = gpio.setup(27, 0, gpio.PULLUP)
        device_id = mobile.imei()
    elseif w5500 then
        -- w5500 以太网, 当前仅Air105支持
        w5500.init(spi.HSPI_0, 24000000, pin.PC14, pin.PC01, pin.PC00)
        w5500.config() --默认是DHCP模式
        w5500.bind(socket.ETH0)
        -- LED = gpio.setup(62, 0, gpio.PULLUP)
    elseif socket or mqtt then
        -- 适配的socket库也OK
        -- 没有其他操作, 单纯给个注释说明
    else
        -- 其他不认识的bsp, 循环提示一下吧
        while 1 do
            sys.wait(1000)
            log.info("bsp", "本bsp可能未适配网络层, 请查证")
        end
    end
    -- 默认都等到联网成功
    sys.waitUntil("IP_READY")
    sys.publish("net_ready", device_id)
end)

sys.taskInit(function()
    -- 等待联网
    local ret, device_id = sys.waitUntil("net_ready")
    -- 下面的是mqtt的参数均可自行修改
    
    --连我们自己自己服务器时需屏蔽掉
    --////////////////////////////////////////////
    client_id = device_id      
    --初始化发布和订阅主题
    pub_topic = "/luatos/pub/" .. device_id 
    sub_topic = "/luatos/sub/" .. device_id
    --////////////////////////////////////////////

    -- 打印一下上报(pub)和下发(sub)的topic名称
    -- 上报: 设备 ---> 服务器
    -- 下发: 设备 <--- 服务器
    -- 可使用mqtt.x等客户端进行调试
    log.info("mqtt", "pub", pub_topic)
    log.info("mqtt", "sub", sub_topic)

    -- 打印一下支持的加密套件, 通常来说, 固件已包含常见的99%的加密套件
    -- if crypto.cipher_suites then
    --     log.info("cipher", "suites", json.encode(crypto.cipher_suites()))
    -- end
    if mqtt == nil then
        while 1 do
            sys.wait(1000)
            log.info("bsp", "本bsp未适配mqtt库, 请查证")
        end
    end

    -------------------------------------
    -------- MQTT 演示代码 --------------
    -------------------------------------
    
    mqttc = mqtt.create(nil, mqtt_host, mqtt_port, mqtt_isssl, ca_file)

    mqttc:auth(client_id,user_name,password) -- client_id必填,其余选填
    -- mqttc:keepalive(240) -- 默认值240s
    mqttc:autoreconn(true, 3000) -- 自动重连机制

    mqttc:on(function(mqtt_client, event, data, payload)
        -- 用户自定义代码
        log.info("mqtt", "event", event, mqtt_client, data, payload)
        if event == "conack" then
            -- 联上了
            sys.publish("mqtt_conack")
            mqtt_client:subscribe(sub_topic)--单主题订阅
            -- mqtt_client:subscribe({[topic1]=1,[topic2]=1,[topic3]=1})--多主题订阅
        elseif event == "recv" then
            --log.info("mqtt", "downlink", "topic", data, "payload", payload)/////////////////
            --sys.publish("mqtt_payload", data, payload)///////////////////////////////////
            
           Auto_Busy_Flag=true
           Data_Server_To_Inverter(payload)     --将服务器发过来的数据转发给变频器RS485接口 
           --ServerPubTopic_Temp=data             --暂存服务器发布主题
           

        elseif event == "sent" then
            --log.info("mqtt", "sent", "pkgid", data)
            
     -- elseif event == "disconnect" then
     -- 非自动重连时,按需重启mqttc
     -- mqtt_client:connect()
      	
        end
    end)

    -- mqttc自动处理重连, 除非自行关闭
    mqttc:connect()
	sys.waitUntil("mqtt_conack")
    while true do
        -- 演示等待其他task发送过来的上报信息
        local ret, topic, data, qos = sys.waitUntil("mqtt_pub", 300000)
        if ret then
            -- 提供关闭本while循环的途径, 不需要可以注释掉
            if topic == "close" then break end
            mqttc:publish(topic, data, qos)
        end
        -- 如果没有其他task上报, 可以写个空等待
        --sys.wait(60000000)
    end
    mqttc:close()
    mqttc = nil
end)


sys.taskInit(function()
    
    while true do
    
        if Auto_Busy_Flag==true then
	       break
	    end
	      
	    sys.wait(8000)
	             
	    Auto_Rank = Auto_Rank + 1
	    if Auto_Rank > Auto_Read_CMD_Num then
	    Auto_Rank = 1
	    end
	      	
	    local Tx_Data=HexStr_To_AssicStr(Auto_Read_AllData_CMD[Auto_Rank])
			    
	    uart.write(uart_id, Tx_Data) 
	    
	    sys.wait(10)
	   
	end
	           
end)



--[[
sys.taskInit(function()
    sys.wait(3000)
    --定义要定时上报的数据
    local data = "123test,"
    --发送的数据质量
    local qos = 0 -- QOS0不带puback, QOS1是带puback的
    while true do
        sys.wait(3000)
        --如果mqttc实例存在，并且mqtt客户端就绪
        if mqttc and mqttc:ready() then
            --发布一个mqtt消息，这个消息的订阅，在mqtt服务器上，后面会介绍如何在mqtt服务器上订阅
            local pkgid = mqttc:publish(pub_topic, data .. os.date(), qos)
        end
    end
end)
--]]


--[[
1、请求数据
ThingsBoard获取设备信息请求的数据格式
{
 	"method":"getValue",
   	"params":{
        	"dy":"01 03 70 03 00 01 6E CA",
       	 	"zs":"01 03 70 00 00 01 9E CA",
        	"dl":"01 03 70 04 00 01 DF 0B"
   	 }
}
获取成功响应的数据格式
{
	"status ":200,
 	"params"{
		"dy":"01 03 02 01 56 39 EA",
		"zs:"01 03 02 61 A8 90 6A",
		"dl:"01 03 02 00 49 79 B2"
	}

}
--]]

--[[
{
    "InVoltage":  "380V",
   	"OutVoltage": "350V",
   	"OutCurrent": "0.8A",
   	"OutPower":   "200W",
	"ErrCode":    "00"
}
--]]